package com.linkallcloud.web.face;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;

import com.linkallcloud.cache.redis.box.RedisTokenBox;
import com.linkallcloud.core.aop.LacAspect;
import com.linkallcloud.core.exception.BaseRuntimeException;
import com.linkallcloud.core.exception.BizException;
import com.linkallcloud.core.exception.Exceptions;
import com.linkallcloud.core.face.message.request.FaceRequest;
import com.linkallcloud.core.lang.Mirror;
import com.linkallcloud.core.lang.Strings;
import com.linkallcloud.core.security.MsgSignObject;
import com.linkallcloud.core.www.ISimpleUser;
import com.linkallcloud.web.face.annotation.Face;
import com.linkallcloud.web.face.annotation.FdMode;
import com.linkallcloud.web.processor.IRequestProcessor;
import com.linkallcloud.web.processor.OriginalProcessor;
import com.linkallcloud.web.processor.PackageJsonProcessor;
import com.linkallcloud.web.processor.PackageXmlProcessor;
import com.linkallcloud.web.processor.SimpleJsonProcessor;
import com.linkallcloud.web.processor.SimpleXmlProcessor;

public abstract class FaceAspect<U extends ISimpleUser> extends LacAspect {

    protected Mirror<U> mirror;
    private static HashMap<String, IRequestProcessor> processors = new HashMap<String, IRequestProcessor>();

    @Autowired
    private RedisTokenBox tokenBox;

    // private PackageJsonProcessor packageJsonProcessor;
    // private PackageXmlProcessor packageXmlProcessor;

    @SuppressWarnings("unchecked")
    public FaceAspect() {
        super();
        try {
            mirror = Mirror.me((Class<U>) Mirror.getTypeParams(getClass())[0]);
        } catch (Throwable e) {
            if (log.isWarnEnabled()) {
                log.warn("!!!Fail to get TypeParams for self!", e);
            }
        }
        processors.put(OriginalProcessor.class.getName(), getOriginalProcessor());
        processors.put(SimpleJsonProcessor.class.getName(), getSimpleJsonProcessor());
        processors.put(SimpleXmlProcessor.class.getName(), getSimpleXmlProcessor());
    }

    // public void setPackageJsonProcessor(PackageJsonProcessor
    // packageJsonProcessor) {
    // this.packageJsonProcessor = packageJsonProcessor;
    // }
    //
    // public void setPackageXmlProcessor(PackageXmlProcessor packageXmlProcessor) {
    // this.packageXmlProcessor = packageXmlProcessor;
    // }

    public Class<U> getSessionUserClass() {
        return (null == mirror) ? null : mirror.getType();
    }

    protected abstract String getThisAppCode();

    protected abstract List<MsgSignObject> loadAppSignObjects();

    protected boolean tokenValidate(ISimpleUser su, String token, FaceRequest fr) {
        String thisAppCode = getThisAppCode();
        if (!Strings.isBlank(thisAppCode) && !Strings.isBlank(su.appCode()) && !Strings.isBlank(fr.getAppCode())) {
            if (thisAppCode.equals(su.appCode()) && thisAppCode.equals(fr.getAppCode())) {
                return true;
            }
        }
        return false;
    }

    protected PackageJsonProcessor getPackageJsonProcessor() {
        List<MsgSignObject> mso = loadAppSignObjects();
        return new PackageJsonProcessor(mso) {
            @Override
            protected ISimpleUser getSessionUserByToken(String token, FaceRequest fr) throws BizException {
                if (!Strings.isBlank(token)) {
                    ISimpleUser su = tokenBox.get(token, getSessionUserClass());
                    if (su != null && tokenValidate(su, token, fr)) {
                        return su;
                    }
                }
                throw new BizException("e.face.login", "根据token加载用户SessionUser发生错误：" + token);
            }

        };
    }

    protected SimpleJsonProcessor getSimpleJsonProcessor() {
        return new SimpleJsonProcessor() {
            @Override
            protected ISimpleUser getSessionUserByToken(String token, FaceRequest fr) throws BizException {
                if (!Strings.isBlank(token)) {
                    ISimpleUser su = tokenBox.get(token, getSessionUserClass());
                    if (su != null && tokenValidate(su, token, fr)) {
                        return su;
                    }
                }
                throw new BizException("e.login", "根据token加载用户SessionUser发生错误：" + token);
            }
        };

    }

    protected PackageXmlProcessor getPackageXmlProcessor() {
        return new PackageXmlProcessor();
    }

    protected SimpleXmlProcessor getSimpleXmlProcessor() {
        return new SimpleXmlProcessor();
    }

    protected OriginalProcessor getOriginalProcessor() {
        return new OriginalProcessor();
    }

    protected String getVersion() {
        return "1.0";
    }

    public Object checkFace(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getMethod(joinPoint);
        Face faceAnno = method.getAnnotation(Face.class);
        if (faceAnno == null) {
            return joinPoint.proceed();
        } else {
            Object result = null;
            IRequestProcessor processor = getRequestProcessor(faceAnno.mode(), faceAnno.simple());
            try {
                result = processor.handle(joinPoint, method, faceAnno);
            } catch (Throwable e) {
                log.error(e.getMessage(), e);
                result = Exceptions.wrapLacErrorResponse(e);
            }
            return processor.packageResult(result, faceAnno);
        }
    }

    private IRequestProcessor getRequestProcessor(FdMode mode, boolean simple) {
        if (FdMode.ORIGINAL.equals(mode)) {
            return getRequestProcessorByName(OriginalProcessor.class.getName());
        } else if (FdMode.JSON.equals(mode)) {
            if (simple == true) {
                return getRequestProcessorByName(SimpleJsonProcessor.class.getName());
            } else {
                return getRequestProcessorByName(PackageJsonProcessor.class.getName());
            }
        } else if (FdMode.XML.equals(mode)) {
            if (simple == true) {
                return getRequestProcessorByName(SimpleXmlProcessor.class.getName());
            } else {
                return getRequestProcessorByName(PackageXmlProcessor.class.getName());
            }
        }
        return null;
    }

    private IRequestProcessor getRequestProcessorByName(String processorClassName) {
        if (processors.containsKey(processorClassName)) {
            return processors.get(processorClassName);
        } else {
            return syncProcessor(processorClassName);
        }
    }

    private synchronized IRequestProcessor syncProcessor(String processorClassName) {
        if (processors.containsKey(processorClassName)) {
            return processors.get(processorClassName);
        } else {
            if (PackageJsonProcessor.class.getName().equals(processorClassName)) {
                PackageJsonProcessor pjp = this.getPackageJsonProcessor();
                if (pjp != null) {
                    processors.put(processorClassName, pjp);
                    return pjp;
                }
                throw new BaseRuntimeException("10000001", "请配置PackageJsonProcessor进行处理");
            } else if (PackageXmlProcessor.class.getName().equals(processorClassName)) {
                PackageXmlProcessor pxp = this.getPackageXmlProcessor();
                if (pxp != null) {
                    processors.put(processorClassName, pxp);
                    return pxp;
                }
                throw new BaseRuntimeException("10000001", "请配置PackageXmlProcessor进行处理");
            } else if (SimpleJsonProcessor.class.getName().equals(processorClassName)) {
                SimpleJsonProcessor processor = getSimpleJsonProcessor();
                processors.put(processorClassName, processor);
                return processor;
            } else if (SimpleXmlProcessor.class.getName().equals(processorClassName)) {
                SimpleXmlProcessor processor = getSimpleXmlProcessor();
                processors.put(processorClassName, processor);
                return processor;
            } else if (OriginalProcessor.class.getName().equals(processorClassName)) {
                OriginalProcessor processor = getOriginalProcessor();
                processors.put(processorClassName, processor);
                return processor;
            } else {
                throw new BaseRuntimeException("10000001", "名称为：" + processorClassName + " 的Processor不存在。");
            }
        }
    }

}
